var express = require('express');
var router = express.Router();
const path = require("path")
const fs = require('fs')
const JSZIP = require('jszip')
const xlsx = require("node-xlsx")
/* GET home page. */
const axios = require('axios');
const log4js = require("../utils/log")
const zipLogger = log4js.getLogger('zip')
const { successRes, errorRes } = require('../utils/response');
const { v4: uuidv4 } = require("uuid");
const { error } = require('console');
const { promisify } = require('util');
const setTimeoutPromise = promisify(setTimeout);
const { exec } = require('child_process');
let expireTime = new Date()
let accessToken = ""
//async过的函数 返回值是Promise 已经是异步的了
async function getAccessToken() {
  let nowTime = new Date()
  if (nowTime > expireTime) {
    //说明accessToken已经过期了
    const { data } = await axios({
      method: "POST",
      url: "https://api.dingtalk.com/v1.0/oauth2/accessToken",
      data: {
        "appKey": "ding6xjc0o3wej1eypms",
        "appSecret": "zlHBt5aJ8aU1n29PGoE0DFgKG7F6_7MSYhVAIizb7MB2zxJhmu6lYRJ_bzG9EiZg"
      },
      headers: {
        "Content-Type": "application/json"
      }
    })
    //提前100秒过期
    expireTime = new Date(new Date().getTime() + (data.expireIn - 100) * 1000)
    accessToken = data.accessToken
    return accessToken
  } else {
    return accessToken
  }
}
const ongoingZipFiles = {};

router.post('/zip_file', async function (req, res, next) {
  try {
    //应该设置一个新的zip 不然所有zip共享文件 下载文件的时候就会叠加了
    const zip = new JSZIP()
    const { datas } = req.body
    if (!datas) {
      return
    }
    //设置存放目录
    const id = uuidv4()
    const pathDir = path.resolve(__dirname, `../public/zip_file/${id}`)
    await new Promise((resolve, reject) => {
      fs.mkdir(pathDir, function (err) {
        if (err) {
          reject(err)
        } else {
          resolve('成功')
        }
      })
    })
    //读取文件流放入目录 不能用forEach forEach不是异步

    await Promise.all(datas.map(async data => {
      const target_path = pathDir + `/${data.name}`
      const response = await axios.get(data.url, { responseType: 'stream' });
      //下面这条一定要await 不然还没加载好后面就执行了
      const to = fs.createWriteStream(target_path)
      response.data.pipe(to);
      //检测写入流结束用await response.data.pipe 检测不到流结束
      await new Promise((resolve, reject) => {
        to.on('finish', function () {
          resolve('finish')
        })
      })
    }))
    //读取目录文件
    let files = []
    // do {
    // } while (files.length != fileUrlArr.length) //前面写入流没有控制的时候 才用了dowhile 现在写入流已经先前完成了
    files = await new Promise((resolve, reject) => {
      fs.readdir(pathDir, function (err, data) {
        if (err) {
          reject(err)
        } else if (data) {
          resolve(data)
        }
      });
    })
    files.forEach((fileName, index) => {
      const fillPath = pathDir + '/' + fileName
      let file = fs.statSync(fillPath)
      //这里file都是文件 要是有目录的话 还需要循环遍历
      zip.file(fileName, fs.readFileSync(fillPath))
    })
    const content = await zip.generateAsync({//设置压缩格式，开始打包
      type: "nodebuffer",//nodejs用
      compression: "DEFLATE",//压缩算法
      compressionOptions: {//压缩级别
        level: 9
      }
    })
    const zipPath = path.resolve(__dirname, `../public/zip_file/${id}.zip`)
    fs.writeFileSync(zipPath, content, "utf-8");//将打包的内容写入 当前目录下的 result.zip中
    ongoingZipFiles[id] = {
      status: 'generated',
      filePath: zipPath,
      folderPath: zipPath.replace(/\.zip$/, ''),
      generatedAt: Date.now(),
      expiresAfterMs: 8 * 60 * 1000,
    };
    successRes(res, '请求成功', `https://www.zyxnbplus.top/get_zip_file/${id}.zip`)
  } catch (err) {
    console.log(err)
    //传递错误日志
    zipLogger.error(err)
    errorRes(res, '服务器错误')
  }
});

router.get("/get_zip_file/:file", async function (req, res, next) {
  const { file } = req.params;
  const fileName = file.split('.')[0]; // 取得不带扩展名的文件名
  const zipFileInfo = ongoingZipFiles[fileName];
  if (!zipFileInfo || !zipFileInfo.filePath) {
    res.status(404).send('压缩包不存在或已过期');
    return;
  }
  // 更新压缩包状态为“正在下载”
  zipFileInfo.status = 'downloading';
  try {
    res.download(zipFileInfo.filePath, file, (err) => {
      if (err && err.message !== 'Request aborted') {
        throw (err)
      }
    });
    // 监听response的close事件，表示传输结束
    res.once('close', () => {
      // 下载完成，可以安全删除文件
      delete ongoingZipFiles[fileName];
      fs.unlinkSync(path.resolve(__dirname, `../public/zip_file/${file}`))
      deleteFolder(path.resolve(__dirname, `../public/zip_file/${file.split('.')[0]}`))
    });

  } catch (err) {
    console.log(err, 'hello');
    zipLogger.error(err);
    // 即使下载出错，也尝试删除文件，但不删除ongoingZipFiles中的记录（因为它可能是其他地方还在使用的记录）
    delete ongoingZipFiles[fileName];
    fs.unlinkSync(path.resolve(__dirname, `../public/zip_file/${file}`))
    deleteFolder(path.resolve(__dirname, `../public/zip_file/${file.split('.')[0]}`))
    
  }
})
// 创建一个定时任务，每隔一分钟检查并清理已过期的ZIP文件记录及物理文件
setInterval(async () => {
  const now = Date.now();
  for (const id in ongoingZipFiles) {
    const fileInfo = ongoingZipFiles[id];
    if (now - fileInfo.generatedAt > fileInfo.expiresAfterMs) {
      try {
        delete ongoingZipFiles[id];
        fs.unlinkSync(path.resolve(__dirname, `../public/zip_file/${id}.zip`));
        deleteFolder(path.resolve(__dirname, `../public/zip_file/${id}`));
        
        console.log(`已自动清理过期ZIP文件：${id}.zip`);
      } catch (err) {
        zipLogger.error(`自动清理过期ZIP文件时出错：${id}.zip`, err);
      }
    }
  }
}, 60 * 1000); // 每隔60秒执行一次

//万能删除文件代码 同步的
function deleteFolder(path) {
  let files = [];
  if (fs.existsSync(path)) {
    files = fs.readdirSync(path);
    files.forEach(function (file, index) {
      let curPath = path + "/" + file;
      if (fs.statSync(curPath).isDirectory()) {
        deleteFolder(curPath);
      } else {
        fs.unlinkSync(curPath);
      }
    });
    fs.rmdirSync(path);
  }
}

router.post("/zip_text", function (req, res, next) {
  try {
    const textArr = JSON.parse(req.body.textArr)
    const data = []
    const title = ['学生', '上传文本']
    data.push(title)
    textArr.forEach(item => {
      data.push([item.name, item.text])
    })
    //配置，设置列宽
    const options = { '!cols': [{ wch: 6 }, { wch: 7 }, { wch: 10 }] };
    //生成二进制数据流
    var buffer = xlsx.build([{ name: "mySheetName", data: data }], options);
    const id = uuidv4()
    const xlsxUrl = path.resolve(__dirname, `../public/zip_text/${id}.xlsx`)
    //写入文件
    fs.appendFileSync(xlsxUrl, buffer)
    successRes(res, '请求成功', `https://www.zyxnbplus.top/get_zip_text/${id}.xlsx`)
  } catch (err) {
    console.log(err)
    zipLogger.error(err)
    errorRes(res, '服务器错误')
  }
})

router.get("/get_zip_text/:xlsx", async function (req, res, next) {
  try {
    const { xlsx } = req.params
    await new Promise((resolve, reject) => {
      res.download(path.resolve(__dirname, `../public/zip_text/${xlsx}`), function (err) {
        if (err && err.message != 'Request aborted') {
          //如果用户取消下载了 就报request aborted请求中断 如果是request aborted就别报错了 不是很重要
          reject(err)
        } else {
          resolve('success')
        }
      })
    })
    fs.unlinkSync(path.resolve(__dirname, `../public/zip_text/${xlsx}`))
  } catch (err) {
    console.log(err)
    zipLogger.error(err)
  }
})




router.post('/zip_file_24.3.26', async function (req, res, next) {
  try {
    //应该设置一个新的zip 不然所有zip共享文件 下载文件的时候就会叠加了
    const zip = new JSZIP()
    const accessToken = await getAccessToken()
    let { fileUrlArr } = req.body
    if (!fileUrlArr) {
      errorRes(res, '没有下载文件')
      return
    }
    fileUrlArr = JSON.parse(fileUrlArr)
    //判断是否有重名
    let isRepeat = false
    let hash = {}
    fileUrlArr.forEach(item => {
      if (!hash[item.name]) {
        hash[item.name] = true
      } else {
        //说明已经重复了
        isRepeat = true
      }
    })
    if (isRepeat) {
      errorRes(res, '文件具有重复名')
      return
    }
    //设置存放目录
    const id = uuidv4()
    const pathDir = path.resolve(__dirname, `../public/zip_file/${id}`)
    await new Promise((resolve, reject) => {
      fs.mkdir(pathDir, function (err) {
        if (err) {
          reject(err)
        } else {
          resolve('成功')
        }
      })
    })
    //读取文件流放入目录 不能用forEach forEach不是异步
    await Promise.all(fileUrlArr.map(async (item, index) => {
      const { data: { result } } = await axios({
        method: 'GET',
        url: 'https://api.dingtalk.com/v1.0/yida/apps/temporaryUrls/APP_M6ELNY9HSUYC02IC5I2L',
        params: {
          systemToken: 'G77664C1IXFHW33NF3FN341OLTN13N2FK13RL35',
          userId: "326139342536593322",
          timeout: 600000,
          fileUrl: item.url,
        },
        headers: {
          "x-acs-dingtalk-access-token": accessToken,
          "Content-Type": "application/json"
        }
      })
      const target_path = pathDir + `/${item.name}`
      const response = await axios.get(result, { responseType: 'stream' });
      //下面这条一定要await 不然还没加载好后面就执行了
      const to = fs.createWriteStream(target_path)
      response.data.pipe(to);
      //检测写入流结束用await response.data.pipe 检测不到流结束
      await new Promise((resolve, reject) => {
        to.on('finish', function () {
          resolve('finish')
        })
      })
    }))
    //读取目录文件
    let files = []
    // do {
    // } while (files.length != fileUrlArr.length) //前面写入流没有控制的时候 才用了dowhile 现在写入流已经先前完成了
    files = await new Promise((resolve, reject) => {
      fs.readdir(pathDir, function (err, data) {
        if (err) {
          reject(err)
        } else if (data) {
          resolve(data)
        }
      });
    })
    files.forEach((fileName, index) => {
      const fillPath = pathDir + '/' + fileName
      let file = fs.statSync(fillPath)
      //这里file都是文件 要是有目录的话 还需要循环遍历
      zip.file(fileName, fs.readFileSync(fillPath))
    })
    const content = await zip.generateAsync({//设置压缩格式，开始打包
      type: "nodebuffer",//nodejs用
      compression: "DEFLATE",//压缩算法
      compressionOptions: {//压缩级别
        level: 9
      }
    })
    const zipPath = path.resolve(__dirname, `../public/zip_file/${id}.zip`)
    fs.writeFileSync(zipPath, content, "utf-8");//将打包的内容写入 当前目录下的 result.zip中
    successRes(res, '请求成功', `https://www.zyxnbplus.top/get_zip_file/${id}.zip`)
  } catch (err) {
    console.log(err)
    //传递错误日志
    zipLogger.error(err)
    errorRes(res, '服务器错误')
  }
});

router.get("/get_zip_file_24.3.26/:file", async function (req, res, next) {
  const { file } = req.params
  try {
    await new Promise((resolve, reject) => {
      res.download(path.resolve(__dirname, `../public/zip_file/${file}`), function (err) {
        if (err && err.message != 'Request aborted') {
          //如果用户取消下载了 就报request aborted请求中断 如果是request aborted就别报错了 不是很重要
          reject(err)
        } else {
          resolve('success')
        }
      })
    })
    fs.unlinkSync(path.resolve(__dirname, `../public/zip_file/${file}`))
    deleteFolder(path.resolve(__dirname, `../public/zip_file/${file.split('.')[0]}`))
  } catch (err) {
    console.log(err, 'hello')
    //就算报错了也要删除文件
    fs.unlinkSync(path.resolve(__dirname, `../public/zip_file/${file}`))
    deleteFolder(path.resolve(__dirname, `../public/zip_file/${file.split('.')[0]}`))
    console.log(err)
    zipLogger.error(err)
    //返回res.download 如果出现错误返回服务器异常会造成nodejs崩溃 download不能返回错误json
  }
})



module.exports = router;
